package core

import (
	"fmt"
	"golang.org/x/net/ipv4"
	"net"
	"syscall"
)

func OpenSenderIP4RawPacketConn(network string, address string) (*ipv4.RawConn, error) {
	conn, err := net.ListenPacket(network, address) // 本地地址
	if err != nil {
		fmt.Printf("listen failed. err: %+v", err)
		return nil, err
	}
	rc, err := ipv4.NewRawConn(conn)
	if err != nil {
		fmt.Printf("open raw conn failed. err: %+v", err)
		return nil, err
	}

	f, err := rc.File()
	fd := f.Fd()
	defer f.Close()

	syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, 1*1024*1024) // 发送缓冲区
	syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, 4096)        // 接收缓冲区
	syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1)
	timeout := syscall.Timeval{Sec: 0, Usec: 500000}
	syscall.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &timeout)
	syscall.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &timeout)

	err = SetBPFDropAll(rc)
	if err != nil {
		fmt.Printf("set bpf failed. err: %+v", err)
		return nil, err
	}

	return rc, nil
}

func OpenReceiverIP4PacketConn(network string, address string) (*ipv4.RawConn, error) {
	conn, err := net.ListenPacket(network, address) // 本地地址
	if err != nil {
		fmt.Printf("listen failed. err: %+v", err)
		return nil, err
	}

	rc, err := ipv4.NewRawConn(conn)
	if err != nil {
		fmt.Printf("open raw conn failed. err: %+v", err)
		return nil, err
	}

	f, err := rc.File()
	fd := f.Fd()
	defer f.Close()

	syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, 4096)        // 发送缓冲区
	syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, 1*1024*1024) // 接收缓冲区
	syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1)

	timeout := syscall.Timeval{Sec: 0, Usec: 100000}
	syscall.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &timeout)
	syscall.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &timeout)

	return rc, nil
}
